package test.concurrent;


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author yachao.guo
 * @date 2019-06-13 18:04
 */
public class BlockedQueue<T> {

    private Object[] items;

    final Lock lock;

    private int count;

    private final Condition notFull;

    private final Condition notEmpty;

    private int enqindex;

    private int deqindex;


    public BlockedQueue(int capacity) {
        items = new Object[capacity];
        lock = new ReentrantLock();
        notEmpty = lock.newCondition();
        notFull = lock.newCondition();
    }

    //入队
    T enq(T t) throws InterruptedException {
        lock.lock();
        try {
            while (count >= items.length) {
                notFull.await();
            }
            final Object[] items = this.items;
            items[enqindex] = t;
            if (++enqindex == items.length) {
                enqindex = 0;
            }
            count++;
            notEmpty.signal();
            return t;
        } finally {
            lock.unlock();
        }
    }

    //出队
    T deq() throws InterruptedException {
        lock.lock();
        try {
            while (0 == count) {
                notEmpty.await();
            }
            final Object[] items = this.items;
            T t = (T) items[deqindex];
            items[deqindex] = null;
            if(++deqindex == items.length){
                deqindex = 0;
            }
            count--;
            notFull.signal();
            return t;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args){
        BlockedQueue<String> blockedQueue = new BlockedQueue<>(2);
        Thread b = new Thread(() -> {

            try {
                System.out.println("出列"+blockedQueue.deq());
                System.out.println("出列"+blockedQueue.deq());
                System.out.println("出列"+blockedQueue.deq());
            } catch (InterruptedException e) {
            }

        });
        b.start();
        Thread a = new Thread(() -> {
            try {
                System.out.println("入列"+blockedQueue.enq("test1"));
                System.out.println("入列"+blockedQueue.enq("test2"));
                System.out.println("入列"+blockedQueue.enq("test3"));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });
        a.start();



    }
}
